package xyz.lilei23.framework.core;

import xyz.lilei23.framework.bean.GenericBeanDefinition;
import xyz.lilei23.framework.bean.parser.BeanConfigParser;
import xyz.lilei23.framework.bean.parser.XmlBeanConfigParser;
import xyz.lilei23.framework.utils.ClassHelper;
import xyz.lilei23.framework.utils.FileHelper;

import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author jack
 * @date 31/07/2021 16:20
 * @version 1.0
 **/
public class ClassPathXmlApplicationContext implements ApplicationContext {

    /**
     * bean工厂
     */
    private BeanFactory beanFactory;

    /**
     * bean配置解析器
     */
    private BeanConfigParser beanConfigParser;


    public ClassPathXmlApplicationContext(String configLocation) {
        beanFactory = new BeanFactory(this);
        beanConfigParser = new XmlBeanConfigParser();
        loadBeanDefinitions(configLocation);
    }

    private void loadBeanDefinitions(String configLocation) {
        try (InputStream in = this.getClass().getResourceAsStream(configLocation.startsWith("/") ? configLocation : "/" + configLocation)) {
            if (in == null) {
                throw new RuntimeException("文件路径异常");
            }
            loadBeanPostProcessors(beanFactory);
            registerBeanPostProcessors(beanFactory);
            List<GenericBeanDefinition> bds = beanConfigParser.parse(in);
            bds.forEach(bd -> beanFactory.setBeanNameByType(bd));
            beanFactory.enableTransaction();
            beanFactory.beanDefinitionProcess(bds);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("加载配置文件异常", e);
        }
    }

    private void loadBeanPostProcessors(BeanFactory beanFactory) {
        List<String> classPaths = new FileHelper().findClassByPath("");
        List<GenericBeanDefinition> genericBeanDefinitions = classPaths.stream().filter(classPath -> {
            try {
                Class<?> aClass = Class.forName(classPath);
                return BeanPostProcessor.class.isAssignableFrom(aClass) && !aClass.isInterface() && !Modifier.isAbstract(aClass.getModifiers());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                return false;
            }
        }).map(clazzPath -> {
            GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
            genericBeanDefinition.setId(ClassHelper.getClassName(clazzPath));
            genericBeanDefinition.setClassName(clazzPath);
            try {
                genericBeanDefinition.setBeanClass(Class.forName(clazzPath));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            genericBeanDefinition.setArgs(ClassHelper.getConstructorArg(genericBeanDefinition.getBeanClass()));
            return genericBeanDefinition;
        }).collect(Collectors.toList());
        registerBeanDefinition(genericBeanDefinitions, beanFactory);
    }

    private void registerBeanDefinition(List<GenericBeanDefinition> genericBeanDefinitions, BeanFactory beanFactory) {
        genericBeanDefinitions.forEach(beanFactory::addBeanDefinition);
    }

    @Override
    public Object getBean(String beanName) {
        return beanFactory.getBean(beanName);
    }

    @Override
    public <R> R getBean(Class<R> clazz) {
        return (R) beanFactory.getBean(clazz);
    }

    /**
     * 注册后置处理器
     */
    protected void registerBeanPostProcessors(BeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory);
    }

}
